package com.jrx.anytxn.customer.processor;

import com.jrx.anytxn.customer.config.MqConfig;
import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Optional;

/**
 * @program: anytxn-cf-transaction
 * @description: RocketMq拦截器
 * @author: xiaoyu.jing
 * @date: 2020-05-07 09:43
 **/
@Order(1)
@Component
public class RocketMQBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(RocketMQBeanPostProcessor.class);
    private ApplicationContext applicationContext;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DefaultRocketMQListenerContainer) {
            //只抓DefaultRocketMQListenerContainer对象，别的bean一律不问
            DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean;
            //利用反射修改container里面的consumeThreadMax字段的值，还好作者使用这个值的时候是在InitializingBean.afterPropertiesSet
            //如果时机在bean的出生阶段，那就不好整了.
            reflectModify(container);
        }
        return bean;
    }

    private DefaultRocketMQListenerContainer reflectModify(DefaultRocketMQListenerContainer container){
        //实现ApplicationContextAware接口，开始接管spring的bean工厂
        //要不然使用@Autowire的方式，注入不了。获取你的配置对象(甚至可以从数据库读取，但是数据库的我没有实验)
        MqConfig config = this.applicationContext.getBean(MqConfig.class);
        //使用反射过滤出来你要修改的consumerThreadMax字段
        Field consumeThreadMaxField = Arrays.stream(container.getClass().getDeclaredFields())
                .filter(field -> field.getName().equals("consumeThreadMax"))
                .findFirst()
                .orElse(null);
        Optional.ofNullable(consumeThreadMaxField)
                .ifPresent(field -> {
                    //别忘设置访问权限为true
                    field.setAccessible(true);
                    try {
                        //设置配置的数值
                        if(0 == config.getMaxThreadSize()){
                            field.setInt(container,5);
                        }else {
                            field.setInt(container, config.getMaxThreadSize());
                        }
                    } catch (IllegalAccessException e) {
                        logger.warn("设置失败了!");
                    }
                });
        return container;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
